package com.tang.common.config.shiroConfig;

import com.tang.common.properties.ShiroProperties;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.mgt.DefaultSessionStorageEvaluator;
import org.apache.shiro.mgt.DefaultSubjectDAO;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.filter.InvalidRequestFilter;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.annotation.Resource;
import javax.servlet.Filter;
import java.util.HashMap;
import java.util.Map;

/**
 * shiro配置类
 */
@Configuration
@EnableConfigurationProperties({ShiroProperties.class})
public class ShiroConfig {
    @Resource
    private ShiroProperties shiroProperties;

    /**
     * 解决shiro版本导致的中文路径无法访问问题
     * @return
     */
    @Bean
    public InvalidRequestFilter invalidRequestFilter() {
        InvalidRequestFilter invalidRequestFilter = new InvalidRequestFilter();
        invalidRequestFilter.setBlockNonAscii(false);
        return invalidRequestFilter;
    }

    /**
     * ShiroFilterFactoryBean
     */
    @Bean
    public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("securityManager") DefaultWebSecurityManager defaultWebSecurityManager){
        ShiroFilterFactoryBean bean = new ShiroFilterFactoryBean();
        // 设置安全管理器
        bean.setSecurityManager(defaultWebSecurityManager);

        // 自定义 JWT 过滤器
        Map<String, Filter> filters = new HashMap<>();
        filters.put("jwt", new JwtFilter());
        filters.put("invalidRequest",invalidRequestFilter());
        bean.setFilters(filters);

        /*
         * 添加shiro的内置过滤器
            anon：无需认证就可以访问
            authc：必须认证了才可以访问
            user：必须拥有 记住我 功能才能用
            perms：拥有对某个资源的权限才能访问
            role：拥有某个角色权限才能访问
         */
        // 配置放行路径
        Map<String, String> filterMap = new HashMap<>(shiroProperties.getPath());

        // 放行knife4j相关路径
        filterMap.put("/doc.html", "anon");
        filterMap.put("/webjars/**", "anon");
        filterMap.put("/v2/api-docs", "anon");
        filterMap.put("/configuration/ui", "anon");
        filterMap.put("/configuration/security", "anon");
        filterMap.put("/swagger-resources/**", "anon");
        System.out.println("开始设置权限：" + filterMap);

        // 其他路径配置
        filterMap.put("/**", "jwt");

        bean.setFilterChainDefinitionMap(filterMap);

        return bean;
    }

    /**
     * DefaultWebSecurityManager
     */
    @Bean(name = "securityManager")
    public DefaultWebSecurityManager getDefaultWebSecurityManager(@Qualifier("userRealm") UserRealm userRealm){
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        // 关联realm
        securityManager.setRealm(userRealm);

        // 关闭Shiro自带的session
        DefaultSubjectDAO subjectDAO = new DefaultSubjectDAO();
        DefaultSessionStorageEvaluator defaultSessionStorageEvaluator = new DefaultSessionStorageEvaluator();
        defaultSessionStorageEvaluator.setSessionStorageEnabled(false);
        subjectDAO.setSessionStorageEvaluator(defaultSessionStorageEvaluator);
        securityManager.setSubjectDAO(subjectDAO);

        return securityManager;
    }

    /**
     * realm
     */
    @Bean
    public UserRealm userRealm(){
        UserRealm userRealm = new UserRealm();
        // 设置自定义凭证匹配器
        userRealm.setCredentialsMatcher(new CustomJwtCredentialsMatcher());
        return userRealm;
    }
}
